#ifndef __MY_FMT_H__
#define __MY_FMT_H__
#include "level.hpp"
#include "message.hpp"
#include <ctime>
#include <vector>
#include <cassert>
#include <sstream>
namespace ltylog
{
    //抽象格式化子项基类
    class FormatItem
    {
    public:
        using ptr=std::shared_ptr<FormatItem>;
        virtual void format(std::ostream &out,LogMsg &msg)=0;
    };
    //派生格式化子项子类—-消息，等级，时间，文件名，行号，线程ID，日志器名，制表符，换行，其他。。。
    class MsgFormatItem : public FormatItem
    {
    public:
        void format(std::ostream &out,LogMsg &msg) override
        {
            out << msg._payload;
        }
    };

    class LevelFormatItem : public FormatItem
    {
    public:
        void format(std::ostream &out,LogMsg &msg) override
        {
            out << LogLevel::toString(msg._level);
        }
    };

    class TimeFormatItem : public FormatItem
    {
    public:
        TimeFormatItem(const std::string &fmt="%H:%M:%S"):_time_fmt(fmt){}
        void format(std::ostream &out,LogMsg &msg) override
        {
            struct tm t;//时间结构体，其中关于时间的数据都有
            localtime_r(&msg._ctime,&t);//获取时间存入t中
            char tmp[32]={0};
            strftime(tmp,31,_time_fmt.c_str(),&t);//把t中的数据转换成字符串
            out << tmp;
        }
    private:
        std::string _time_fmt;//%H:%M:%S 时分秒
    };

    class FileFormatItem : public FormatItem
    {
    public:
        void format(std::ostream &out,LogMsg &msg) override
        {
            out << msg._file;
        }
    };

    class LineFormatItem : public FormatItem
    {
    public:
        void format(std::ostream &out,LogMsg &msg) override
        {
            out << msg._line;
        }
    };

    class ThreadFormatItem : public FormatItem
    {
    public:
        void format(std::ostream &out,LogMsg &msg) override
        {
            out << msg._tid;
        }
    };

    class LoggerFormatItem : public FormatItem
    {
    public:
        void format(std::ostream &out,LogMsg &msg) override
        {
            out << msg._logger;
        }
    };

    class TabFormatItem : public FormatItem
    {
    public:
        void format(std::ostream &out,LogMsg &msg) override
        {
            out << "\t";
        }
    };

    class NLineFormatItem : public FormatItem
    {
    public:
        void format(std::ostream &out,LogMsg &msg) override
        {
            out << "\n";
        }
    };

    class OtherFormatItem : public FormatItem
    {
    public:
        OtherFormatItem(const std::string &str):_str(str){}
        void format(std::ostream &out,LogMsg &msg) override
        {
            out << _str;
        }
    private:
        std::string _str;
    };

    /*
        %d  日期
        %t  线程ID
        %c  日志器名称
        %f  源码文件名
        %l  源码行号
        %p  日志级别
        %T  制表符缩进
        %m  主体消息
        %n  换行
    */
    class Formatter 
    {
    public:
        using ptr=std::shared_ptr<Formatter>;
        Formatter(const std::string &pattern="[%d{%H:%M:%S}][%t][%c][%f:%l][%p]%T%m%n"):
            _pattern(pattern){
            assert(parsePattern());//parsePattern一定成功
            };
        //对msg进行格式化
        void format(std::ostream &out,LogMsg &msg)//返回字符串到io流中
        {
            for(auto &item:_items)
            {
                item->format(out,msg);
            }
        }
        std::string format(LogMsg &msg)//返回msg格式化后的字符串string
        {
            std::stringstream ss;
            format(ss,msg);
            return ss.str();
        }
    private:
        //把日志各个子项解析到_items中
        bool parsePattern()
        {
            std::vector<std::pair<std::string,std::string>> fmt_order;
            size_t pos=0;
            std::string key,val;
            while(pos<_pattern.size())
            {
            //1、处理原始字符串--判断是否是‘%’，不是就是原始字符
            //abcde[%d{%H:%M:%S}][%p]%T%m%n
                if(_pattern[pos]!='%')
                {
                    val.push_back(_pattern[pos++]);
                    continue;
                }
                //能过上面就代表pos位置是‘%’
                if(pos+1<_pattern.size() && _pattern[pos+1]=='%')//遇到 "%%" 时
                {
                    val.push_back('%');
                    pos+=2;
                    continue;
                }
                //能走到这代表%后是个格式化字符,上面走完代表原始字符串处理完毕
                if(!val.empty())
                {
                    fmt_order.push_back(std::make_pair("",val));
                    val.clear();
                }

                //开始格式化字符的处理，此时pos指向'%'
                pos+=1;//现在指向格式化字符
                if(pos==_pattern.size())
                {
                    std::cout<<"%后没有对应的格式化字符\n";
                    return false;
                }
                key=_pattern[pos];
                //指向格式化字符后的字符:%d{},指向'{'
                pos+=1;
                if(pos<_pattern.size() && _pattern[pos]=='{')
                {
                    pos+=1;//指向子规则的起始位置:%d{%H:%M:%S},指向H前面的%
                    while(pos<_pattern.size() && _pattern[pos]!='}')
                    {
                        val.push_back(_pattern[pos++]);
                    }
                    //走完后跳出循环，则代表没有遇到'}'，代表格式错误
                    if(pos==_pattern.size()) 
                    {
                        std::cout<< "子规则{}匹配出错\n";
                        return false;
                    }
                    pos+=1;//循环结束后应该指向‘}’位置，向后走一步开始下次处理位置

                }
                fmt_order.push_back(std::make_pair(key,val));
                key.clear();
                val.clear();
            }
            //2、根据解析得到的数据初始化格式化子项数组成员
            for(auto& it:fmt_order)
            {
                _items.push_back(createItem(it.first,it.second));
            }
            return true;
        }

        //根据不同格式化字符创建不同格式化子项对象
        FormatItem::ptr createItem(const std::string &key,const std::string &val)
        {
        using std::make_shared;
        if(key=="d") return make_shared<TimeFormatItem>(val);
        if(key=="t") return make_shared<ThreadFormatItem>();
        if(key=="c") return make_shared<LoggerFormatItem>();
        if(key=="f") return make_shared<FileFormatItem>();
        if(key=="l") return make_shared<LineFormatItem>();
        if(key=="p") return make_shared<LevelFormatItem>();
        if(key=="T") return make_shared<TabFormatItem>();
        if(key=="m") return make_shared<MsgFormatItem>();
        if(key=="n") return make_shared<NLineFormatItem>();
        if(key=="" ) return make_shared<OtherFormatItem>(val);
        std::cout<<"没有对应的格式化字符：%"<<key<<std::endl;
        abort();
        return FormatItem::ptr();
        }
    private:
        std::string _pattern;//格式化规则字符串:abcde[%d{%H:%M:%S}][%p]%T%m%n
        std::vector<FormatItem::ptr> _items;
    };
}

#endif